<template>
  <div class="KgQA">
    <el-card class="askWindow" body-style="height:100%;padding:10px">
      <div class="content" ref="qaContent">
        <div class="top-fixed">
          <div class="space-holder" ref="spaceHolder"></div>
          <div class="title" ref="qaTitle">知识图谱智能问答
            <el-button class="backButton" type="primary" icon="el-icon-back" @click="backRoute" size="small">返回</el-button></div>

          <div class="qa-input-line" ref="qaInput">
            <div class="input-container">
              <el-autocomplete
                  ref="input"
                  v-model="question"
                  style="width:100%;"
                  :fetch-suggestions="querySearch"
                  placeholder="请输入问题"
                  :select-when-unmatched="true"
                  @select="handleSelect"
                  @keydown.enter.native="handleEnter($event)"
              ></el-autocomplete>
            </div>
            <div class="btn-container">
              <el-button class="button" type="danger" icon="el-icon-close" @click="cancelAsk" size="small">撤回</el-button>
              <el-button class="button" type="primary" icon="el-icon-search" @click="ask" size="small"
              >提问</el-button
              >
            </div>
            <div class="qa-divider">
              <el-divider></el-divider>
            </div>
          </div>
        </div>

        <div class="answer-content" ref="qaAnswer">
          <div
            class="defaultAnswers"
            v-if="mainAnswerArr.length === 0 && additionAnswerArr.length === 0"
          >
            <div
              class="defaultAnswer"
              v-for="(item, index) in defaultAnswerArr"
              :key="index + 1"
              @click="setDefaultAnswer(item)"
            >
              <el-card shadow="hover" body-style="padding: 5px">
                {{ item }}
              </el-card>
            </div>
          </div>

          <div
            class="answer-container"
            v-for="item in mainAnswerArr"
            :key="item.key"
          >
            <MultipleAnswer v-if="item.type === 'MULTIPLE'" @to-rec="toRec" :answer="item" />
            <ResourceAnswer v-if="item.type === 'RESOURCE' || item.type === 'CLASS'" @to-rec="toRec" :answer="item" />
            <el-button
              title="绘制图谱"
              class="draw-btn"
              type="primary"
              icon="el-icon-edit"
              circle
              @click="paint(item.content.kg)"
            ></el-button>
          </div>
          <div class="noMore" v-if="mainAnswerArr.length === 0 && additionAnswerArr.length === 0">
            还没有找到任何结果...
          </div>

          <el-divider class="addition" v-if="additionAnswerArr.length !== 0"
            >附加结果</el-divider
          >

          <div
            class="answer-container"
            v-for="item in additionAnswerArr"
            :key="item.key"
          >
            <MultipleAnswer v-if="item.type === 'MULTIPLE'" @to-rec="toRec" :answer="item" />
            <ResourceAnswer v-if="item.type === 'RESOURCE' || item.type === 'CLASS'" @to-rec="toRec" :answer="item" />
            <el-button
              title="绘制图谱"
              class="draw-btn"
              type="primary"
              icon="el-icon-edit"
              circle
              @click="paint(item.content.kg)"
            ></el-button>
          </div>
          <div
            class="noMore"
            v-if="mainAnswerArr.length !== 0 || additionAnswerArr.length !== 0"
          >
            没有更多结果了
          </div>
        </div>
      </div>
      <el-button class="toTopButton" icon="el-icon-arrow-up" v-if="hasScroll" @click="scrollToTop">回到顶部</el-button>
    </el-card>
    <el-card class="paintWindow" body-style="height:100%;width:100%;padding:0">
      <qa-paint class="qaPaint" :key="paintingKey" :kg="kg" />
    </el-card>
  </div>
</template>

<script>
import { CANCEL_MESSAGE } from "@/config";
import { askAPI } from "@/api/kfqa/kgqa";
import MultipleAnswer from "@/views/kgQA/components/MultipleAnswer";
import ResourceAnswer from "@/views/kgQA/components/ResourceAnswer";
import QaPaint from "@/views/kgQA/components/qaPaint";

function throttle(fn, interval) {
  let last = 0
  return function () {
    let context = this
    let args = arguments
    let now = +new Date()
    if (now - last >= interval) {
      last = now;
      fn.apply(context, args);
    }
  }
}

//答案封装对象
let AnswerForAsk = function(question, mainAnswer, additionAnswer, recommend) {
  this.question = question;
  this.mainAnswer = mainAnswer;
  this.additionAnswer = additionAnswer;
  this.recommend = recommend;
};

export default {
  name: "kgqa",
  components: { QaPaint, ResourceAnswer, MultipleAnswer },
  data() {
    return {
      question: "", //提出的问题
      curQuestionForAnswer: "",
      cancelTokenSource: null, //用于终止一次提问
      loadingMessage: {
        ask: null
      },
      historyAsk: [],
      hasMore: true,
      gotAnswer: 0,
      answerStep: 10,
      isLoadMore: false, // 是否是懒加载到底时的新请求
      historyList: [],
      curSelected: -1,
      mainAnswerArr: [],
      additionAnswerArr: [],
      defaultAnswerArr: [
        "精神过敏的相关疾病是什么?",
        "小儿感冒颗粒的药品类型是",
        "星形病毒胃肠炎的临床症状？？"
      ],
      paintingKey: Symbol(), //通知绘图更新key
      kg: null,
      hasScroll: false,
      scrollThrottle: null,
      askThrottle: null,
      newQuestion: false,
    };
  },
  mounted() {
    this.scrollThrottle = throttle(this.requestMoreAnswer, 1000);
    this.askThrottle = throttle(this.ask, 1000);
    this.$nextTick(function () {
      this.$refs.qaContent.addEventListener('scroll', this.onScroll);
    })
  },
  methods: {
    backRoute(){
      window.history.go(-1);
    },
    cancelAsk(){
      this.historyAsk.pop()
      this.question = this.historyAsk.pop()
      console.log(this.historyAsk + " historyAsk")
      this.ask()

    },
    scrollToTop() {
      this.$refs.qaContent.scrollTop = 0;
      this.hasScroll = false;
    },
    // 懒加载相关
    getScrollTop() {
      // 获取滚动条当前的位置
      return this.$refs.qaContent.scrollTop;
    },
    getClientHeight() {
      // 获取当前可视范围的高度
      return this.$refs.qaContent.clientHeight;
    },
    getScrollHeight() {
      // 获取组件完整的高度
      return this.$refs.qaContent.scrollHeight;
    },
    onScroll() {
      this.hasScroll = this.getScrollTop() > 500;
      // 滚动事件触发下拉加载
      if (
        this.getScrollHeight() - this.getClientHeight() - this.getScrollTop() <=
        100
      ) {
        this.scrollThrottle();
      }
    },
    // 问题历史记录相关
    querySearch(queryString, cb) {
      let questionHistory = [];
      this.historyList.forEach(item=>{
        questionHistory.push({"value": item.question});
      });
      let results = queryString ? questionHistory.filter(this.createFilter(queryString)) : questionHistory;
      // 调用 callback 返回建议列表的数据
      cb(results);
    },
    createFilter(queryString) {
      return (history) => {
        return (history.value.indexOf(queryString) === 0);
      };
    },
    handleSelect(item) {
      this.question = item.value;
      this.askThrottle();
    },
    handleEnter(event) {
      if (
        event.key === "Enter" ||
        event.code === "Enter" ||
        event.keyCode === 13
      ) {
        event.returnValue = false;
        event.target.blur();
        this.askThrottle();
      }
    },
    toRec(question) {
      this.question = question;
      this.askThrottle();
    },
    ask() {
      if(this.historyAsk.indexOf(this.question) > -1){
         //
      }else{
        this.historyAsk.push(this.question)
      }

      if (this.question.length === 0) {
        this.$message.warning("还没有输入任何问题");
        return;
      }
      if (this.curQuestionForAnswer === this.question) return;
      //取消上一次提问
      if (this.cancelTokenSource != null) {
        this.cancelTokenSource.cancel(CANCEL_MESSAGE);
      }
      //产生加载提示
      if (this.loadingMessage.ask != null) {
        this.loadingMessage.ask.close();
        this.loadingMessage.ask = null;
      }
      this.scrollToTop();
      this.loadingMessage.ask = this.$message.loading();
      //寻找搜索历史
      this.isLoadMore = false;
      this.hasMore = true;
      this.hasScroll = false;
      for (let i = 0; i < this.historyList.length; i++) {
        let item = this.historyList[i];
        if (item.question === this.question) {
          // this.$message("已查询过此问题");
          this.curSelected = i;
          this.resolve(item);
          this.updateCurGotAnswer();
          this.curQuestionForAnswer = this.question;
          this.loadingMessage.ask.close();
          this.loadingMessage.ask = null;
          return;
        }
      }
      this.newQuestion = true;
      this.requestAnswer();
    },
    requestMoreAnswer() {
      if (this.hasMore) {
        // 请求更多答案
        console.log('请求更多答案');
        this.isLoadMore = true;
        this.updateCurGotAnswer();
        this.requestAnswer();
      } else {
        console.log('没有更多内容了');
      }
    },
    requestAnswer () {
      if (!this.isLoadMore) {
        this.gotAnswer = 0;
      }
      //发送提问请求
      this.cancelTokenSource = askAPI(
          {
            question: this.question,
            step: this.answerStep,
            cur: this.gotAnswer,
          },
          res => {
            if (!this.newQuestion && res.mainAnswer === null && res.additionAnswer === null) {
              this.hasMore = false;
              return;
            }
            this.hasMore = true;
            let answer = new AnswerForAsk(
                this.question,
                res.mainAnswer,
                res.additionAnswer,
                "无",
            );
            if (!this.isLoadMore) {
              this.historyList.push(answer);
              this.curSelected = this.historyList.length - 1;
            }
            this.resolve(answer);
            this.curQuestionForAnswer = this.question;
            this.updateCurGotAnswer();
          },
          errorMessage => {
            this.$message.error("加载失败:" + errorMessage);
          },
          () => {
            this.cancelTokenSource = null;
            this.newQuestion = false;
            if (this.loadingMessage.ask !== null) {
              this.loadingMessage.ask.close();
              this.loadingMessage.ask = null;
            }
          }
      );
    },
    resolve(answerForAsk) {
      if (!this.isLoadMore) {
        this.mainAnswerArr = [];
        this.additionAnswerArr = [];
      }
      let newMainAnswer = [];
      this.resolveOne(answerForAsk.mainAnswer, this.mainAnswerArr, newMainAnswer);
      let newAddAnswer = [];
      this.resolveOne(answerForAsk.additionAnswer, this.additionAnswerArr, newAddAnswer);
      if (typeof(this.curSelected) == "undefined"
          || this.curSelected === null
          || typeof(this.curSelected) != "number"
          || this.curSelected < 0
          || this.curSelected >= this.historyList.length) {
        console.log('下标错误', this.curSelected);
        return;
      }
      if (this.isLoadMore) {
        if (this.historyList[this.curSelected].mainAnswer !== null) {
          this.historyList[this.curSelected].mainAnswer.content.push(...newMainAnswer);
        }
        if (this.historyList[this.curSelected].additionAnswer !== null) {
          this.historyList[this.curSelected].additionAnswer.content.push(...newAddAnswer);
        }
      }
    },
    resolveOne(answer, arr, res) {
      if (answer == null) return;
      if (answer.type === "ANSWER_LIST") {
        answer.content.forEach(item => {
          this.resolveOne(item, arr, res);
        });
      } else {
        answer.key = Symbol();
        arr.push(answer);
        res.push(answer);
      }
    },
    updateCurGotAnswer() {
      this.gotAnswer = (() => {
        let mainLength = this.mainAnswerArr.length;
        let additionLength = this.additionAnswerArr.length;
        return mainLength + additionLength;
      })();
    },
    paint(kg) {
      this.kg = kg;
      this.paintingKey = Symbol();
    },
    setDefaultAnswer(q) {
      this.question = q;
    }
  }
};
</script>

<style scoped>
.KgQA {
  height: 100%;
}
.askWindow {
  margin-top: 1%;
  margin-left: 1%;
  float: left;
  box-sizing: border-box;
  height: 96%;
  width: 35%;
}
.askWindow .content {
  height: 96%;
  overflow: auto;
  margin-top: 50px;
}
.askWindow .content .answer-content {
  margin-top: 140px;
}
.askWindow .content .top-fixed {
}
.askWindow .content .top-fixed .space-holder{
  background: rgba(255,255,255,1);
  z-index: 2;
  position: fixed;
  height: 120px;
  /*width: 31.55%;*/
  width: 32.5%;
}
.askWindow .content .top-fixed .title {
  top: 22px;
  z-index: 99999;
  position: fixed;
  width: 31%;
  text-align: left;
  font-size: 20px;
  font-weight: bold;
}
.askWindow .content .top-fixed .qa-input-line {
  top: 80px;
  z-index: 99999;
  position: fixed;
  width: 31%;
}
.askWindow .content .top-fixed .qa-input-line:after {
  content: "";
  height: 0;
  z-index: 99999;
  line-height: 0;
  display: block;
  visibility: hidden;
  clear: both;
}
.askWindow .content .top-fixed .qa-input-line .qa-divider {
  height: 0;
  top: 160px;
  position: fixed;
  z-index: 999;
  width: 31%;
}
.askWindow .content .top-fixed .qa-input-line .input-container {
  z-index: 999999;
  margin-bottom: 20px;
  /*width: 70%;*/
  /*float: left;*/
}
.askWindow .content .top-fixed .qa-input-line .btn-container .button {
  float: right;
  margin-left: 10px;
}

.paintWindow {
  margin-top: 1%;
  margin-left: 1%;
  height: 96%;
  width: 61%;
  float: left;
}

.askWindow .toTopButton {
  position: relative;
  left: 35%;
  bottom: 5%;
}

.answer-container {
  position: relative;
  margin-bottom: 10px;
}
.answer-container .draw-btn {
  position: absolute;
  right: 5px;
  top: 5px;
  opacity: 0.3;
}
.answer-container .draw-btn:hover {
  opacity: 1;
}

.noMore {
  color: #7f7f7f;
  font-size: 15px;
}

.defaultAnswers {
  margin-bottom: 10px;
}
.defaultAnswers:after {
  content: "";
  height: 0;
  line-height: 0;
  display: block;
  visibility: hidden;
  clear: both;
}
.defaultAnswer {
  float: left;
  margin-bottom: 5px;
  margin-right: 5px;
  display: inline-block;
  font-size: 15px;
  color: #7f7f7f;
}
.defaultAnswer:hover {
  cursor: pointer;
}

.qaPaint {
  position: relative;
  margin-top: 1%;
  margin-left: 1%;
  height: 98%;
  width: 98%;
}
.addition {
  font-size: 20px;
}

.backButton{
  float: right;
  margin-left: 50px;
}
</style>
